package com.nulldev.util.web.HttpServer3;

import static com.nulldev.util.web.HttpServer3.util.HttpServerUtil.__has_header;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.io.IOUtils;
import com.nulldev.util.web.HttpServer3.pages.v3.HttpPage3;

public class ReadRequest implements AutoCloseable {
	public static final String[] DEFAULT_APPLY = new String[]
		{ "request" };

	private final Map<String, String> headers;
	private final InputStream data_streamed;
	private final AtomicReference<Duration> timeout = new AtomicReference<Duration>(null);
	private final AtomicReference<String[]> timeout_apply_to = new AtomicReference<String[]>(DEFAULT_APPLY);

	public ReadRequest(final Map<String, String> headers) {
		this(headers, null);
	}

	public ReadRequest(final Map<String, String> headers, final InputStream data_streamed) {
		this.headers = headers;
		this.data_streamed = data_streamed;
	}

	private final AtomicReference<HashMap<String, String>> legacyHeaders = new AtomicReference<HashMap<String, String>>();

	public HashMap<String, String> headers_legacy() {
		if (this.legacyHeaders.get() == null)
			return this.legacyHeaders.updateAndGet((e) -> {
				return new HashMap<String, String>(this.headers);
			});
		return this.legacyHeaders.get();
	}

	public ReadRequest resetLegacyHeaders() {
		this.legacyHeaders.lazySet(null);
		return this;
	}

	public Map<String, String> headers() {
		return this.headers;
	}

	public InputStream stream() {
		return this.data_streamed;
	}

	public ReadRequest setTimeoutDuration(final Duration dur) {
//FIXME:	if (this.timeout != null) return this; (we should be protected once NX is mainlined)
		this.timeout.lazySet(dur);
		return this;
	}

	public ReadRequest setTimeoutApplyTo(final String... values) { // FIXME: (we should be protected once NX is mainlined)
		this.timeout_apply_to.lazySet(values);
		return this;
	}

	public Duration getTimeoutDuration() {
		return this.timeout.get();
	}

	public boolean hasTimeoutDuration() {
		return this.timeout.get() != null && this.timeout.get() != Duration.ZERO;
	}

	public String[] getTimeoutApplyTo() {
		if (this.timeout_apply_to.get() == null || this.timeout_apply_to.get().length == 0)
			return DEFAULT_APPLY;
		return this.timeout_apply_to.get();
	}

	public boolean appliesTimeoutTo(final String section) {
		if (section == null || section.isEmpty())
			return false;
		if (this.timeout_apply_to.get() == null || this.timeout_apply_to.get().length == 0)
			return false;
		return ArrayUtils.StringArrayUtils.containsString(this.timeout_apply_to.get(), section);
	}

	@Override
	public void close() throws IOException {
		if (this.legacyHeaders.get() != null)
			this.legacyHeaders.get().clear();
		this.headers.clear();
		IOUtils.closeQuietly(this.data_streamed);
	}

	public int length() {
		return 0;
	}

	public boolean hasStream() {
		return this.data_streamed != null && this.data_streamed != HttpPage3.BLANK_IO_STREAM;
	}

	public boolean header(final String string) {
		if (string == null || string.isEmpty())
			return false;
		return this.headers.containsKey(string) || this.headers.containsKey(string.toLowerCase());
	}

	public boolean headerIs(final String key, final String value) {
		if ((key == null || key.isEmpty()) || (value == null || value.isEmpty()))
			return false;
		if (!__has_header(this.headers, key)) {
			return false;
		} else {
			return this.headers.get(key).equals(value);
		}
	}

	public boolean isTrailersAllowed() {
		return this.headerIs("TE", "1");
	}
}
